import re
import sys
import operator
import os
import argparse
from ast import literal_eval

def safe_eval_c_expression(expr):
    """安全地评估 C 语言表达式"""
    # 移除所有空格
    expr = re.sub(r'\s+', '', expr)
    
    # 定义支持的运算符
    operators = {
        '+': operator.add,
        '-': operator.sub,
        '*': operator.mul,
        '/': operator.floordiv,  # 整数除法
        '%': operator.mod,
        '<<': operator.lshift,
        '>>': operator.rshift,
        '&': operator.and_,
        '|': operator.or_,
        '^': operator.xor
    }
    
    # 简单的表达式解析器
    def parse_expression(expr):
        # 处理括号
        while '(' in expr:
            # 找到最内层的括号
            open_idx = expr.rfind('(')
            close_idx = expr.find(')', open_idx)
            if close_idx == -1:
                raise ValueError("括号不匹配")
            
            # 递归计算括号内的表达式
            inner_result = parse_expression(expr[open_idx + 1:close_idx])
            # 替换括号及其内容
            expr = expr[:open_idx] + str(inner_result) + expr[close_idx + 1:]
        
        # 按优先级处理运算符
        for ops in [['*', '/', '%'], ['+', '-'], ['<<', '>>'], ['&'], ['^'], ['|']]:
            while any(op in expr for op in ops):
                # 找到当前优先级的运算符
                match = re.search(r'(\d+)([' + re.escape(''.join(ops)) + r'])(\d+)', expr)
                if not match:
                    break
                
                left = int(match.group(1))
                op = match.group(2)
                right = int(match.group(3))
                
                # 执行运算
                result = operators[op](left, right)
                
                # 替换表达式
                expr = expr[:match.start()] + str(result) + expr[match.end():]
        
        # 最终结果应该是一个数字
        try:
            return int(expr)
        except ValueError:
            raise ValueError(f"无法解析表达式: {expr}")
    
    try:
        # 尝试使用我们的简单解析器
        return parse_expression(expr)
    except Exception as e:
        # 如果失败，尝试使用 Python 的 eval（但要小心安全风险）
        try:
            # 替换 C 语言特定的运算符
            expr = expr.replace('/', '//')  # 整数除法
            return int(eval(expr))
        except Exception:
            raise ValueError(f"无法解析表达式: {expr}")

def extract_hex_from_c_array(input_file, array_name):
    """从 C 数组文件中提取指定数组的十六进制数据"""
    # 转义数组名中的特殊字符
    escaped_name = re.escape(array_name)
    
    # 修改正则表达式以捕获数组长度（如果存在）
    pattern = re.compile(
        r'[^;]*\b' + escaped_name + r'\s*(?:\[([^\]]*)\])?\s*=\s*\{([\s\S]*?)\};',
        re.DOTALL | re.IGNORECASE
    )
    
    try:
        # 首先尝试使用 UTF-8 编码
        with open(input_file, 'r', encoding='utf-8') as f:
            content = f.read()
    except UnicodeDecodeError:
        try:
            # 如果 UTF-8 失败，尝试使用 Latin-1 编码（它可以读取任何字节）
            with open(input_file, 'r', encoding='latin-1') as f:
                content = f.read()
        except Exception as e:
            raise ValueError(f"无法读取文件 '{input_file}': {str(e)}")
    
    match = pattern.search(content)
    if not match:
        raise ValueError(f"未找到数组 '{array_name}' 的定义")
    
    # 获取数组长度（如果指定）和数据
    array_size = None
    if match.group(1):  # 如果捕获到了数组长度
        try:
            # 尝试将数组长度解析为整数或表达式
            size_str = match.group(1).strip()
            # 移除可能的空格和注释
            size_str = re.sub(r'\/\/.*$', '', size_str)
            size_str = re.sub(r'\/\*.*?\*\/', '', size_str)
            size_str = size_str.strip()
            
            # 尝试解析表达式
            try:
                # 首先尝试直接转换为整数
                array_size = int(size_str)
                print(f"[信息] 检测到数组长度限制: {array_size} 字节")
            except ValueError:
                # 如果失败，尝试解析 C 语言表达式
                try:
                    array_size = safe_eval_c_expression(size_str)
                    print(f"[信息] 检测到数组长度表达式: {size_str} = {array_size} 字节")
                except Exception as e:
                    print(f"[警告] 无法解析数组长度表达式: '{size_str}'，将使用实际数据长度: {str(e)}")
        except Exception as e:
            print(f"[警告] 解析数组长度时出错: {str(e)}")
    
    # 提取并清理十六进制数据
    hex_data = []
    hex_str = match.group(2)
    
    # 使用正则表达式匹配所有十六进制数
    hex_pattern = re.compile(r'0[xX][0-9a-fA-F]+|[0-9a-fA-F]+[hH]|\d+')
    for num in hex_pattern.finditer(hex_str):
        value = num.group()
        # 处理不同格式的十六进制数
        if value.endswith('h') or value.endswith('H'):
            value = value[:-1]
        elif value.startswith('0x') or value.startswith('0X'):
            value = value[2:]
        else:
            # 将十进制转换为十六进制
            try:
                value = hex(int(value))[2:].zfill(2)
            except ValueError:
                continue
        hex_data.append(value)
    
    # 如果指定了数组长度，则限制提取的数据长度
    original_length = len(hex_data)
    if array_size is not None:
        if array_size < original_length:
            hex_data = hex_data[:array_size]
            print(f"[信息] 根据数组长度限制，从 {original_length} 字节截取到 {array_size} 字节")
        elif array_size > original_length:
            print(f"[警告] 数组声明长度 ({array_size}) 大于实际数据长度 ({original_length})，使用实际数据长度")
    
    return hex_data

def hex_to_bin(hex_data, output_file):
    """将十六进制数据列表转换为二进制文件"""
    try:
        # 将十六进制字符串列表转换为字节
        byte_data = bytes.fromhex(''.join(hex_data))
    except ValueError as e:
        raise ValueError(f"无效的十六进制数据: {e}")
    
    with open(output_file, 'wb') as f:
        f.write(byte_data)
    return byte_data

def verify_binary_data(bin_data, hex_data):
    """验证生成的二进制文件与原始数组数据是否匹配"""
    if len(bin_data) != len(hex_data):
        return False, f"数据长度不匹配: 二进制文件 {len(bin_data)} 字节, 原始数组 {len(hex_data)} 字节"
    
    original_bytes = bytes.fromhex(''.join(hex_data))
    if bin_data != original_bytes:
        return False, "数据内容不匹配"
    
    return True, "数据验证通过"

def list_arrays_in_file(input_file):
    """列出文件中所有的数组定义"""
    try:
        # 首先尝试使用 UTF-8 编码
        with open(input_file, 'r', encoding='utf-8') as f:
            content = f.read()
    except UnicodeDecodeError:
        try:
            # 如果 UTF-8 失败，尝试使用 Latin-1 编码
            with open(input_file, 'r', encoding='latin-1') as f:
                content = f.read()
        except Exception as e:
            raise ValueError(f"无法读取文件 '{input_file}': {str(e)}")
    
    # 改进的正则表达式，匹配各种格式的数组定义
    array_pattern = re.compile(
        r'\b(?:const\s+)?(?:unsigned\s+)?(?:char|int|short|long)\s+(\w+)\s*(?:\[([^\]]*)\])?\s*=\s*\{',
        re.DOTALL
    )
    
    matches = array_pattern.findall(content)
    
    arrays = []
    for name, size in matches:
        size_str = size.strip() if size else "未指定"
        # 尝试解析表达式
        if size_str != "未指定":
            try:
                size_value = safe_eval_c_expression(size_str)
                size_str = f"{size_str} = {size_value}"
            except:
                pass
        arrays.append((name, size_str))
    
    return arrays

def process_file(input_file, output_file=None, array_name=None):
    """处理文件，提取数组并生成二进制文件"""
    try:
        # 获取文件中的所有数组
        arrays = list_arrays_in_file(input_file)
        
        if not arrays:
            print(f"[错误] 在文件 '{input_file}' 中未找到任何数组定义")
            return False
        
        # 如果未指定数组名称或指定的数组不存在，使用第一个找到的数组
        if array_name is None:
            array_name = arrays[0][0]
            print(f"[信息] 未指定数组名称，使用第一个找到的数组: '{array_name}'")
        elif not any(name == array_name for name, _ in arrays):
            print(f"[警告] 未找到数组 '{array_name}' 的定义")
            print("文件中找到的数组定义:")
            for i, (name, size) in enumerate(arrays, 1):
                print(f"  {i}. {name} [大小: {size}]")
            
            array_name = arrays[0][0]
            print(f"[信息] 使用第一个找到的数组: '{array_name}'")
        
        # 如果未指定输出文件名，使用数组名称作为输出文件名
        if output_file is None:
            output_file = f"{array_name}.bin"
            print(f"[信息] 未指定输出文件名，使用数组名称作为输出文件名: '{output_file}'")
        
        # 提取指定数组的十六进制数据
        hex_data = extract_hex_from_c_array(input_file, array_name)
        
        # 转换为二进制文件
        bin_data = hex_to_bin(hex_data, output_file)
        
        # 验证数据
        is_valid, msg = verify_binary_data(bin_data, hex_data)
        if is_valid:
            print(f"[验证通过] 生成的二进制文件与原始数组数据匹配")
        else:
            print(f"[警告] {msg}")
            
        print(f"[完成] 生成二进制文件: {output_file} ({len(bin_data)} 字节)")
        return True
        
    except Exception as e:
        print(f"[错误] {str(e)}")
        return False

def main():
    # 设置命令行参数解析
    parser = argparse.ArgumentParser(
        description='将C语言数组转换为二进制文件',
        usage='%(prog)s [选项] 输入文件 [输出文件] [数组名称]'
    )
    
    parser.add_argument('input_file', help='输入的C语言头文件')
    parser.add_argument('output_file', nargs='?', default=None, 
                       help='输出的二进制文件（可选，默认为数组名.bin）')
    parser.add_argument('array_name', nargs='?', default=None,
                       help='要提取的数组名称（可选，默认为第一个找到的数组）')
    parser.add_argument('-l', '--list', action='store_true',
                       help='列出文件中的所有数组定义')
    
    args = parser.parse_args()

    # 处理列出数组的情况
    if args.list:
        try:
            arrays = list_arrays_in_file(args.input_file)
            if arrays:
                print(f"文件 '{args.input_file}' 中找到的数组定义:")
                for i, (name, size) in enumerate(arrays, 1):
                    print(f"  {i}. {name} [大小: {size}]")
            else:
                print(f"在文件 '{args.input_file}' 中未找到数组定义")
        except Exception as e:
            print(f"[错误] {str(e)}")
        sys.exit(0)
    
    # 处理转换数组的情况
    try:
        success = process_file(args.input_file, args.output_file, args.array_name)
        sys.exit(0 if success else 1)
    except Exception as e:
        print(f"[错误] {str(e)}")
        sys.exit(1)

if __name__ == "__main__":
    main()